home *** CD-ROM | disk | FTP | other *** search
/ Skunkware 5 / Skunkware 5.iso / src / X11 / xpaint-2.1.1 / protocol.c < prev    next >
C/C++ Source or Header  |  1995-05-03  |  9KB  |  397 lines

  1. /* +-------------------------------------------------------------------+ */
  2. /* | Copyright 1993, David Koblas (koblas@netcom.com)                  | */
  3. /* |                                                                   | */
  4. /* | Permission to use, copy, modify, and to distribute this software  | */
  5. /* | and its documentation for any purpose is hereby granted without   | */
  6. /* | fee, provided that the above copyright notice appear in all       | */
  7. /* | copies and that both that copyright notice and this permission    | */
  8. /* | notice appear in supporting documentation.  There is no           | */
  9. /* | representations about the suitability of this software for        | */
  10. /* | any purpose.  this software is provided "as is" without express   | */
  11. /* | or implied warranty.                                              | */
  12. /* |                                                                   | */
  13. /* +-------------------------------------------------------------------+ */
  14.  
  15. #include <X11/Intrinsic.h>
  16. #include <X11/StringDefs.h>
  17. #include <X11/Xatom.h>
  18. #include <X11/cursorfont.h>
  19. #include <sys/time.h>
  20.  
  21. extern XImage *NewXImage(Display*,Visual*,int,int,int);
  22.  
  23. typedef void    (*func_t)(Widget, void *, XEvent *);
  24.  
  25. typedef struct li_s {
  26.     /*
  27.     **  Destroy request info
  28.     */
  29.     void        *data;
  30.     func_t        func;
  31.  
  32.     /*
  33.     **  Info for watch cursor
  34.     */
  35.     int        watchCount, computingCount;
  36.     Widget        shell, parent;
  37.     Window        win;
  38.     Display        *dpy;
  39.     struct li_s    *next;
  40. } LocalInfo;
  41.  
  42. #define    DO_MAP(l)    ((l)->watchCount + (l)->computingCount > 0)
  43.  
  44. #include "bitmaps/wait1.xbm"
  45. #include "bitmaps/wait2.xbm"
  46. #include "bitmaps/wait3.xbm"
  47. #include "bitmaps/wait4.xbm"
  48.  
  49. static Atom        delwin = None, protocols = None;
  50. static LocalInfo    *head = NULL;
  51.  
  52. static int        currentCursor = 0;
  53. static Cursor        watchCursor = None;
  54.  
  55. static struct {
  56.     Cursor        cursor;
  57.     int        width, height;
  58.     unsigned char    *bits;
  59. } cursorInfo[] = {
  60.     { None, wait1_width, wait1_height, wait1_bits },
  61.     { None, wait2_width, wait2_height, wait2_bits },
  62.     { None, wait3_width, wait3_height, wait3_bits },
  63.     { None, wait4_width, wait4_height, wait4_bits },
  64. };
  65.  
  66. static void initCursors(Widget w)
  67. {
  68.     static int    inited = False;
  69.     Display        *dpy = XtDisplay(w);
  70.     Screen        *screen = XtScreen(w);
  71.     GC        gc = None;
  72.     Pixmap        pix, mask;
  73.     int        i, width, height;
  74.     XImage        *src, *msk;
  75.     int        x, y;
  76.     XColor        xcols[2];
  77.  
  78.     if (inited)
  79.         return;
  80.     inited = True;
  81.  
  82.     xcols[0].pixel = BlackPixelOfScreen(screen);
  83.     xcols[1].pixel = WhitePixelOfScreen(screen);
  84.  
  85.     XQueryColors(dpy, DefaultColormapOfScreen(screen), xcols, XtNumber(xcols));
  86.  
  87.     for (i = 0; i < XtNumber(cursorInfo); i++) {
  88.         width = cursorInfo[i].width;
  89.         height = cursorInfo[i].height;
  90.         pix = XCreatePixmapFromBitmapData(dpy, RootWindowOfScreen(screen),
  91.                 (char*)cursorInfo[i].bits, width, height, True, False, 1);
  92.         src = XGetImage(dpy, pix, 0, 0, width, height, AllPlanes, ZPixmap);
  93.         msk = NewXImage(dpy, NULL, 1, width, height);
  94.         for (y = 0; y < height; y++) {
  95.             for (x = 0; x < width; x++) {
  96.                 Boolean    flg = (Boolean)XGetPixel(src, x, y);
  97.  
  98.                 if (!flg && x > 0)
  99.                     flg = XGetPixel(src, x - 1, y);
  100.                 if (!flg && x < width - 1)
  101.                     flg = XGetPixel(src, x + 1, y);
  102.                 if (!flg && y > 0)
  103.                     flg = XGetPixel(src, x, y - 1);
  104.                 if (!flg && y < height - 1)
  105.                     flg = XGetPixel(src, x, y + 1);
  106.                 XPutPixel(msk, x, y, flg);
  107.             }
  108.         }
  109.  
  110.         mask = XCreatePixmap(dpy, pix, width, height, 1);
  111.         if (gc == None)
  112.             gc = XCreateGC(dpy, mask, 0, 0);
  113.         XPutImage(dpy, mask, gc, msk, 0, 0, 0, 0, width, height);
  114.  
  115.         XDestroyImage(src);
  116.         XDestroyImage(msk);
  117.  
  118.         cursorInfo[i].cursor = XCreatePixmapCursor(dpy, pix, mask, 
  119.                 &xcols[0], &xcols[1], width / 2, height / 2);
  120.         XFreePixmap(dpy, pix);
  121.         XFreePixmap(dpy, mask);
  122.     }
  123.     if (gc != None)
  124.         XFreeGC(dpy, gc);
  125. }
  126.  
  127. static void destroyCallback(Widget w, XtPointer data, XtPointer junk)
  128. {
  129.     LocalInfo    *l = (LocalInfo *)data;
  130.     LocalInfo    *cur, **pp;
  131.  
  132.     for (cur = *(pp = &head); cur != NULL && cur != l; cur = *(pp = &cur->next));
  133.  
  134.     if (cur == NULL)
  135.         return;
  136.  
  137.     *pp = cur->next;
  138.     
  139.     XtFree((XtPointer)data);
  140. }
  141.  
  142. static void handler(Widget w, XtPointer lArg, XEvent *eventArg, Boolean *junk)
  143. {
  144.     XClientMessageEvent    *event = (XClientMessageEvent*)eventArg;
  145.     LocalInfo        *l = (LocalInfo *)lArg;
  146.     if (event->type != ClientMessage)
  147.         return;
  148.  
  149.     if (event->message_type == protocols && event->data.l[0] == delwin)
  150.         l->func(w, l->data, eventArg);
  151. }
  152.  
  153. static void add(Widget w, LocalInfo *l)
  154. {
  155.     unsigned long         valuemask;
  156.     XSetWindowAttributes    attributes;
  157.     /*
  158.     **  Set up the shell destroy info
  159.     */
  160.     XtAddRawEventHandler(w, 0, True, handler, (XtPointer)l);
  161.     XChangeProperty(XtDisplay(w), XtWindow(w), protocols, 
  162.             XA_ATOM, 32, PropModeReplace, 
  163.             (unsigned char *) &delwin, 1);
  164.  
  165.     /* 
  166.     **  Now set up watch cursor information
  167.     **
  168.     **  Ignore device events while the busy cursor is displayed.
  169.     */
  170.     valuemask = CWDontPropagate | CWCursor;
  171.     attributes.do_not_propagate_mask =  (KeyPressMask | KeyReleaseMask |
  172.             ButtonPressMask | ButtonReleaseMask | PointerMotionMask);
  173.     if (watchCursor == None)
  174.         watchCursor = XCreateFontCursor(XtDisplay(w), XC_watch);
  175.     attributes.cursor = watchCursor;
  176.  
  177.     /*
  178.     ** The window will be as big as the display screen, and clipped by
  179.     ** its own parent window, so we never have to worry about resizing
  180.     */
  181.     l->win = XCreateWindow(XtDisplay(w), XtWindow(w), 0, 0,
  182.             WidthOfScreen(XtScreen(w)), HeightOfScreen(XtScreen(w)), 
  183.             (unsigned int) 0, 0, InputOnly,
  184.             CopyFromParent, valuemask, &attributes);
  185.  
  186.     if (DO_MAP(l))
  187.         XMapRaised(l->dpy, l->win);
  188. }
  189.  
  190.  
  191. static void realize(Widget w, XtPointer ldataArg, XEvent *event, Boolean *junk)
  192. {
  193.     if (event->type == MapNotify) {
  194.         XtRemoveEventHandler(w, StructureNotifyMask, False, 
  195.                     realize, ldataArg);
  196.         add(w, (LocalInfo*)ldataArg);
  197.     }
  198. }
  199.  
  200. void AddDestroyCallback(Widget w, func_t func, void *data)
  201. {
  202.     LocalInfo     *l;
  203.  
  204.     if (delwin == None)
  205.         delwin = XInternAtom(XtDisplay(w), "WM_DELETE_WINDOW", FALSE);
  206.     if (protocols == None)
  207.         protocols = XInternAtom(XtDisplay(w), "WM_PROTOCOLS", FALSE);
  208.  
  209.     initCursors(w);
  210.  
  211.     if (delwin == None || protocols == None)
  212.         return;
  213.  
  214.     l = XtNew(LocalInfo);
  215.     l->data  = data;
  216.     l->func  = func;
  217.     l->win   = None;
  218.     l->dpy   = XtDisplay(w);
  219.     l->watchCount = 0;
  220.     l->computingCount = 0;
  221.     l->shell = w;
  222.     l->parent      = None;
  223.  
  224.     if (!XtIsRealized(w))
  225.         XtAddEventHandler(w, StructureNotifyMask, False, realize, (XtPointer)l);
  226.     else
  227.         add(w, l);
  228.  
  229.     XtAddCallback(w, XtNdestroyCallback, destroyCallback, (XtPointer)l);
  230.  
  231.     l->next = head;
  232.     head = l;
  233. }
  234.  
  235. static Boolean setBusy(LocalInfo *cur, Boolean isWatch, Boolean flag)
  236. {
  237.     Boolean        doFlush = False;
  238.  
  239.     if (isWatch) {
  240.         if (flag) {
  241.             cur->watchCount++;
  242.         } else {
  243.             if (cur->watchCount == 0)
  244.                 return False;
  245.             cur->watchCount--;
  246.         }
  247.     } else {
  248.         if (flag) {
  249.             cur->computingCount++;
  250.         } else {
  251.             if (cur->computingCount == 0)
  252.                 return False;
  253.             cur->computingCount--;
  254.         }
  255.     }
  256.  
  257.     if (cur->win == None)
  258.         return False;
  259.  
  260.     if (cur->watchCount == 0 && cur->computingCount == 0) {
  261.         XUnmapWindow(cur->dpy, cur->win);
  262.         return False;
  263.     }
  264.  
  265.     if (cur->watchCount == 1) {
  266.         if (isWatch) {
  267.             XMapRaised(cur->dpy, cur->win);
  268.             XDefineCursor(cur->dpy, cur->win, watchCursor);
  269.             doFlush = True;
  270.         }
  271.     } else if (cur->computingCount == 1) {
  272.         if (!isWatch) {
  273.             XMapRaised(cur->dpy, cur->win);
  274.             XDefineCursor(cur->dpy, cur->win, cursorInfo[currentCursor].cursor);
  275.             doFlush = True;
  276.         }
  277.     }
  278.  
  279.     return doFlush;
  280. }
  281.  
  282. void StateSetBusyWatch(Boolean flag)
  283. {
  284.     LocalInfo    *cur;
  285.     Boolean        doFlush = False;
  286.  
  287.     for (cur = head; cur != NULL; cur = cur->next) 
  288.         doFlush |= setBusy(cur, True, flag);
  289.  
  290.     if (doFlush)
  291.         XFlush(head->dpy);
  292. }
  293.  
  294. void StateSetBusy(Boolean flag)
  295. {
  296.     LocalInfo    *cur;
  297.     Boolean        doFlush = False;
  298.  
  299.     for (cur = head; cur != NULL; cur = cur->next) 
  300.         doFlush |= setBusy(cur, False, flag);
  301.  
  302.     if (doFlush)
  303.         XFlush(head->dpy);
  304. }
  305.  
  306. void StateShellBusy(Widget w, Boolean flag)
  307. {
  308.     LocalInfo    *cur;
  309.     Boolean        doFlush = False;
  310.  
  311.     if (w == None)
  312.         return;
  313.  
  314.     while (!XtIsShell(w))
  315.         w = XtParent(w);
  316.  
  317.     for (cur = head; cur != NULL; cur = cur->next) {
  318.         if (cur->shell == w) {
  319.             doFlush |= setBusy(cur, True, flag);
  320.         } else if (cur->parent == w) {
  321.             StateShellBusy(cur->shell, flag);
  322.         }
  323.     }
  324.     if (doFlush)
  325.         XFlush(head->dpy);
  326. }
  327.  
  328. void StateAddParent(Widget w, Widget parent)
  329. {
  330.     LocalInfo    *cur;
  331.  
  332.     if (w == None || parent == None)
  333.         return;
  334.  
  335.     while (!XtIsShell(parent))
  336.         parent = XtParent(parent);
  337.     while (!XtIsShell(w))
  338.         w = XtParent(w);
  339.  
  340.     for (cur = head; cur != NULL && cur->shell != w; cur = cur->next)
  341.         ;
  342.     if (cur == NULL)
  343.         return;
  344.  
  345.     cur->parent = parent;
  346. }
  347.  
  348. void StateTimeStep()
  349. {
  350.     static Boolean        inited = False;
  351.     static struct timeval    lastTime;
  352.     struct timeval        nowTime;
  353.     Boolean            done = False, need = False;
  354.     Cursor            c;
  355.     LocalInfo        *cur;
  356.  
  357.     for (cur = head; cur != NULL; cur = cur->next)
  358.         if (cur->watchCount == 0 && cur->computingCount != 0 && cur->win != None)
  359.             need = True;
  360.  
  361.     if (!need)
  362.         return;
  363.  
  364.     gettimeofday(&nowTime, NULL);
  365.     if (inited) {
  366.         long    ds, dus;
  367.  
  368.         dus = nowTime.tv_usec - lastTime.tv_usec;
  369.         ds  = nowTime.tv_sec  - lastTime.tv_sec;
  370.         if (dus < 0) {
  371.             ds--;
  372.             dus += 1000000;
  373.         }
  374.         if (ds == 0 && dus < 200000)
  375.             return;
  376.     } else {
  377.         inited = True;
  378.     }
  379.     lastTime = nowTime;
  380.     
  381.  
  382.     if (++currentCursor == XtNumber(cursorInfo))
  383.         currentCursor = 0;
  384.  
  385.     c = cursorInfo[currentCursor].cursor;
  386.  
  387.     for (cur = head; cur != NULL; cur = cur->next) {
  388.         if (cur->watchCount == 0 && cur->computingCount != 0 && cur->win != None) {
  389.             XDefineCursor(cur->dpy, cur->win, c);
  390.             done = True;
  391.         }
  392.     }
  393.  
  394.     if (done)
  395.         XFlush(head->dpy);
  396. }
  397.